package org.example.mallchat.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.example.mallchat.adapter.TextBuilder;
import org.example.mallchat.dao.UserDao;
import org.example.mallchat.domain.entity.User;
import org.example.mallchat.service.UserService;
import org.example.mallchat.service.WxMsgService;
import org.example.mallchat.websocket.service.WebSocketService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @author: zzh
 * @date: 2024/12/18 14:41:01
 * @version: 1.0
 */
//微信服务实现类
@Service
public class WxMsgServiceImpl implements WxMsgService {

    @Resource
    @Lazy
    private WebSocketService webSocketService;

    @Resource
    private UserService userService;

    // 授权链接 注意替换为自己的appid和redirect_uri授权成功回调的地址,以及scope=snsapi_userinfo
    // 注意：这里的redirect_uri需要在微信公众平台中配置，并且需要在微信公众平台中配置授权成功回调的地址
    public static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    @Value("${wx.mp.callback}")
    private String callback;

    @Resource
    private UserDao userDao;

    /**
     * 扫码触发
     * @param wxMpService
     * @param wxMpXmlMessage
     * @return
     */
    @Override
    public WxMpXmlOutMessage scan(WxMpService wxMpService, WxMpXmlMessage wxMpXmlMessage) throws UnsupportedEncodingException {
        // 获取用户的openId
        String openId = wxMpXmlMessage.getFromUser();
        // 对code进行处理，因为关注和扫码的code是不一样的，所以需要区分
        String code = wxMpXmlMessage.getEventKey();
        Integer loginCode = getEventKey(code);

        // 判断这个用户是否注册过 根据openId查询用户
        User user = userDao.getUserByOpenId(openId);
        boolean registered = ObjectUtil.isNotNull(user);
        boolean authorized = registered && StrUtil.isNotBlank(user.getAvatar());// 如果用户有头像就说明授权过了
        // 如果用户注册并且授权了
        if (registered && authorized) {
            // 直接返回消息 走登录成功，讲code找到channel推送消息
            webSocketService.scanLoginSuccess(loginCode,user.getId());
            return null;
        }

        // 未注册，这先将用户信息注册到数据库中
        if (!registered) {
            // 注册用户
            userService.register(openId);
        }

        // 扫码事件处理
        // 拼接授权url
        // 保存openId和code，用于授权成功后拿到code
        // 同时channel形式推送消息给前端，提示等待用户授权登录
        webSocketService.saveOpenIdCode(openId, loginCode);
        System.out.println("扫码事件触发");
        webSocketService.sendMsgWaitUserClickAuth(loginCode);
        System.out.println("callback：" + callback);
        String authorizeUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callback + "/wx/portal/public/callBack"));
        System.out.println("授权链接：" + authorizeUrl);
        // 封装url让用户点击登录请求，(其实请求就是去拿到用户信息！)并且授权
        return TextBuilder.build("请点击链接授权：<a href=\"" + authorizeUrl + "\">登录</a>", wxMpXmlMessage, wxMpService);
    }

    @Override
    public void authorize(WxOAuth2UserInfo userInfo) {
        // 授权成功后，将用户信息保存到数据库中
        User user = userDao.getUserByOpenId(userInfo.getOpenid());
        user.setOpenId(userInfo.getOpenid());
        user.setName(userInfo.getNickname());
        user.setAvatar(userInfo.getHeadImgUrl());
        // 根据openId查询用户 并且修改用户信息ById
        userDao.updateById(user);

        // 根据openId拿到code，最终拿到channel
        Integer codeByOpenId = webSocketService.getCodeByOpenId(user.getOpenId());
        // 直接返回消息 走登录成功，讲code找到channel推送消息
        webSocketService.scanLoginSuccess(codeByOpenId,user.getId());
    }

    private Integer getEventKey(String code) {
        if (code == null){
            return null;
        }
        return Integer.parseInt(code.replace("qrscene_", ""));
    }
}
